package main

import (
	"bufio"
	"fmt"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"
)

func main() {
	/*
		1.构建连接string
		2.进行websocket服务器连接
		3.启动数据发送和接受，运行协程
		4.进行select阻塞
	*/
	var wg sync.WaitGroup
	link := url.URL{Scheme: "ws", Host: baseUrl, Path: "/socket"}
	log.Println("connecting to ", link.String())
	// websocket程序入口
	conn, _, err := websocket.DefaultDialer.Dial(link.String(), nil)
	if err != nil {
		fmt.Println("backend down")
		log.Println(err)
		return
	}
	defer func() {
		if err = conn.Close(); err != nil {
			log.Println(err)
			return
		}
	}()
	// 后面再进行升级，现在处理任务，进行通知全局退出协程，当cancelFunc执行的时候进行该操作
	//_, cancel := context.WithCancel(context.Background())
	//defer cancel()
	// 进行post传文件处理
	urlSend := url.URL{Scheme: "http", Host: baseUrl, Path: "/file"}
	wsFunc(&wg, conn, urlSend)

	pingFunc(&wg)

	//sendFile(fmt.Sprintf("%s/%s", basePlace, "nihao.txt"), urlSend.String())

	// 主协程反正使用select卡住，后面的服务都使用协程跑
	// select {}
	// 改用waitGroup退出ok, err := Login(userMsg)
	wg.Wait()
}

//func Login(msg userMsg) (bool, error) {
//
//}

type UserMsg struct {
	username string
	password string
	addr     string
	birthday string
}

const (
	basePlace = "/home/hufeng/GolandProjects/hufeng_review/clientFunc"
	baseUrl   = "localhost:2025"
)

func pingFunc(wg *sync.WaitGroup) {
	// 每1min向后端ping一次tcp连接
	wg.Add(1)
	go func() {
		pingMin(wg)
	}()
}

func wsFunc(wg *sync.WaitGroup, conn *websocket.Conn, sendUrl url.URL) {
	wg.Add(1)
	go func() {
		receiveMsg(conn, wg)
	}()

	// 使用os的stdin获取发送数据
	wg.Add(1)
	go func() {
		sendMsg(conn, wg, sendUrl)
	}()

}

// pingMin 定时发送Get请求
func pingMin(wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		time.Sleep(10 * time.Second)
		resp, err := http.Get(fmt.Sprintf("%s%s", "http://localhost:2025", "/ping"))
		if err != nil {
			log.Fatal(err)
		}
		if _, err = io.ReadAll(resp.Body); err != nil {
			log.Println(err)
			return
		}
		// fmt.Println(resp.StatusCode)
		if err = resp.Body.Close(); err != nil {
			log.Println(err)
			return
		}
		// fmt.Println(string(body))
	}

}

func sendMsg(conn *websocket.Conn, wg *sync.WaitGroup, sendUrl url.URL) {
	defer wg.Done()
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		//// 如果包含的是发送文件的命令，进行发送文件，否则进行websocket通信。
		//if strings.HasPrefix(scanner.Text(), "file") {
		//	// 定义发送文件命令
		//	split := strings.Split(scanner.Text(), ":")
		//	fmt.Println(split)
		//	file := fmt.Sprintf("%s/%s", basePlace, split[1])
		//	res, err := sendFile(fmt.Sprintf("%s/%s", basePlace, split[1]), sendUrl.String())
		//	fmt.Println(file, res, err)
		//} else {
		//	if err := conn.WriteMessage(1, []byte(scanner.Text())); err != nil {
		//		log.Fatal(err)
		//	}
		//}
		// 使用Switch
		cmd := strings.Split(scanner.Text(), ":")[0]
		text := scanner.Text()
		switch cmd {
		case "file":
			// 定义发送文件命令
			split := strings.Split(text, ":")
			file := fmt.Sprintf("%s/%s", basePlace, split[1])
			fmt.Println(split, file)
			res, err := sendFile(fmt.Sprintf("%s/%s", basePlace, split[1]), sendUrl.String())
			fmt.Println(file, res, err)
		case "login":
			// 这里要设定一个规范：设置login之后的字段要求，其实可以是tcp请求，也可以直接websocket，这个很方便
			split := strings.Split(text, ":")
			// 规定确定：第一个username，第二个password
			msg := AddMsg(split[1])
			fmt.Println(msg)
		default:
			if err := conn.WriteMessage(1, []byte(scanner.Text())); err != nil {
				log.Fatal(err)
			}
		}
	}
}

func AddMsg(msg string) *UserMsg {
	userMessage := &UserMsg{}
	split := strings.Split(msg, ",")
	for _, x := range split {
		title := strings.Split(x, "-")[0]
		switch title {
		case "username":
			userMessage.username = strings.Split(x, "-")[1]
		case "password":
			userMessage.password = strings.Split(x, "-")[1]
		case "address":
			userMessage.addr = strings.Split(x, "-")[1]
		case "birthday":
			userMessage.birthday = strings.Split(x, "-")[1]
		}
	}
	return userMessage
}

func receiveMsg(conn *websocket.Conn, wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		// 当出现后端服务器宕机的情况，我们不应该直接退出，应该进行简单处理
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			fmt.Println("error on continue listen to websocket")
			log.Println(err)
			return
		}
		fmt.Printf("type: %d,msg: %s\n", messageType, string(p))
	}
}
